package cn.javass.dp.flyweight.example5;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 享元工厂，通常实现为单例
 */
public class FlyweightFactory {
    private static FlyweightFactory factory = new FlyweightFactory();
    private FlyweightFactory() {
        //启动清除缓存值的线程
        Thread t = new CleanCache();
        t.start();
    }
    public static FlyweightFactory getInstance() {
        return factory;
    }
    /**
     * 缓存多个享元对象
     */
    private Map<String, Flyweight> fsMap = new HashMap<>();

    /**
     * 用来缓存享元对象的缓存配置
     */
    private Map<String, CacheConfModel> cacheConfMap = new HashMap<>();

    /**
     * 用来记录缓存对象被引用的次数
     */
    private Map<String, Integer> countMap = new HashMap<>();

    /**
     * 缓存有效时间
     */
    private final long DURABLE_TIME = 6*1000L;

    /**
     * 获取某个享元被使用的次数
     * @param key  享元的key
     * @return
     */
    public synchronized int getUserTime(String key) {
        Integer count = countMap.get(key);
        if (count == null) {
            count = 0;
        }
        return count;
    }


    /**
     * 获取 key 对应的享元对象
     * @param key
     * @return
     */
    public synchronized Flyweight getFlyweight(String key) {
        Flyweight f = fsMap.get(key);
        if (f == null) {
            f = new AuthorizationFlyweight(key);
            fsMap.put(key, f);

            //同时设置引用计数
            countMap.put(key, 1);
            //同时设置缓存配置数据
            CacheConfModel cm = new CacheConfModel();
            cm.setBeginTime(System.currentTimeMillis());
            cm.setForever(false);
            cm.setDurableTime(DURABLE_TIME);
            cacheConfMap.put(key, cm);
        } else {
            //表示还在使用，重新设置缓存开始时间
            CacheConfModel cm = cacheConfMap.get(key);
            cm.setBeginTime(System.currentTimeMillis());
            this.cacheConfMap.put(key, cm);
            Integer count = countMap.get(key);
            count++;
            countMap.put(key, count);
        }
        return f;
    }

    private synchronized void removeFlyweight(String key) {
        this.fsMap.remove(key);
        this.cacheConfMap.remove(key);
        this.countMap.remove(key);
    }

    private class CleanCache extends Thread {
        @Override
        public void run() {
            while (true) {
                Set<String> tempSet = new HashSet<>();
                Set<String> set = cacheConfMap.keySet();

                for (String key: set) {
                    CacheConfModel ccm = cacheConfMap.get(key);
                    if (System.currentTimeMillis() - ccm.getBeginTime() >= ccm.getDurableTime()) {
                        //记录缓存配置中需要清理的key
                        tempSet.add(key);
                    }
                }
                //真正清理缓存数据
                for (String key : tempSet) {
                    FlyweightFactory.getInstance().removeFlyweight(key);
                }

                System.out.println("now thread" + fsMap.size() + ",fsMap==" + fsMap.keySet());

                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
